import wx
import os.path
import keyword
import wx.stc as stc

from utils import tracer
import stylesDefination

class EditorStyle(object):
  def __init__(self, language):
    self._language = language
    self._stylesDef = stylesDefination.getDefination(language)
    self._editView = None

  def setEditorView(self, owner):
    if owner is None:
      #Todo: clear style setting of owner here
      self._editView = None
    else:
      self._editView = owner
      self.setStyle()

  def getCommentSymbols(self):
    return self._stylesDef.getCommentSymbols()

  # -- set highlight style -------------------------------------------------------------
  def setStyle(self):
    # set lexer
    self._editView.SetLexer(self.getLexer(self._language))
    self._editView.SetKeyWords(0, " ".join(keyword.kwlist))

    self._editView.SetProperty('fold', '1')
    self._editView.SetProperty('tab.timmy.whinge.level', '1')
    self._editView.SetMargins(0, 0)
    
    styles = self._stylesDef.getStyles()

    # set indentation and white space
    if not styles is None and styles.has_key('Indent'):
      self.setIndentationAndWhiteSpace(styles['Indent'])
    else:
      self.setIndentationAndWhiteSpace()
      
    # set eol
    if not styles is None and styles.has_key('EOL'):
      self.setEOL(styles['EOL'])
    else:
      self.setEOL()
      
    # set edge mode
    if not styles is None and styles.has_key('Edge'):
      self.setEdgeMode(styles['Edge'])
    else:
      self.setEdgeMode()
      
    # set margins
    self.setMargins()

    # set marker
    if not styles is None and styles.has_key('Marker'):
      self.setMarker(styles['Marker'])
    else:
      self.setMarker()

    # set global style
    if not styles is None and styles.has_key('Font'):
      self.setGlobalStyle(styles['Font'])
    else:
      self.setGlobalStyle()    
      
    # set highlight style
    if not styles is None and styles.has_key('Highlight'):
      self.setHighlightStyle(styles['Highlight'])
    else:
      self.setHighlightStyle()
      
    # set caret foreground
    if not styles is None and styles.has_key('Caret'):
      self.setCaretFg(styles['Caret'])
    else:
      self.setCaretFg()

  def getLexer(self, language):
    # set highlight language with SetLexer method
    # follow values could be used:
    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  Value	                Folding?	          properties

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_ADA	        no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_ASP	        no	                  see wxSTC_LEX_HTML

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_AUTOMATIC	N.A.	                  N.A.

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_AVE	        no?	                  "fold" (not implemented?)

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_BAAN	        yes	                  "styling.within.preprocessor"

    #                                                     "fold.comment"

    #                                                     "fold.compact"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_BATCH	        no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_BULLANT	no?	                  "fold" (not implemented?)

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_CONF	        no	                  no (Apache config files)

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_CONTAINER	N.A.	                  N.A.

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_CPP	        yes	                  "styling.within.preprocessor"

    #                                                     "fold.comment"

    #                                                     "fold.preprocessor"

    #                                                     "fold.compact"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_DIFF	        no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_EIFFEL	        yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_EIFFELKW	yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_ERRORLIST	no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_HTML	        no	                  "asp.default.language" (javascript)

    #                                                     "fold.html"

    #                                                     "fold"

    #                                                     "fold.compact"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_LATEX	        no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_LISP	        yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_LUA	        yes	                  "fold.compact"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_MAKEFILE	no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_MATLAB	        yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_NNCRONTAB	no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_NULL	        N.A.	                  Null language just handles the protocol but does nothing. Use for plain text.

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_PASCAL	        yes	                  "fold.comment"

    #                                                     "fold.preprocessor"

    #                                                     "fold.compact"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_PERL	        yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_PHP	        no	                  see wxSTC_LEX_HTML

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_PROPERTIES	no	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_PYTHON	        yes	                  "fold.comment.python"

    #                                                     "fold.quotes.python"

    #                                                     "tab.timmy.whinge.level"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_RUBY	        yes	                  "tab.timmy.whinge.level"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_SCRIPTOL	Unknown	                  Although defined, support doesn't exist.

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_SQL	        yes	                  "fold"

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_TCL	        yes	                  see wxSTC_LEX_CPP

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_VB	        yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_VBSCRIPT	yes	                  no

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_XCODE	        Unknown	                  Although defined, support doesn't exist. It's for for DevelopMentor's GenX product.

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------

    #  wxSTC_LEX_XML	        no	                  see wxSTC_LEX_HTML

    # +-----------------------+------------------------+---------------------------------------------------------------------------------------
    if self._language.lower() == stylesDefination.LANGUAGE_PYTHON:
      return stc.STC_LEX_PYTHON
    elif self._language.lower() == stylesDefination.LANGUAGE_PYTHON:
      return stc.STC_LEX_XML
    else:
      return stc.STC_LEX_NULL

  def setIndentationAndWhiteSpace(self, indent_style=None):
    style = None
    if not indent_style is None:
      style = indent_style
    else:
      style = self._stylesDef.getDefaultIndentStyles()

    # set indent size
    if style.has_key('Size') and style['Size'] != '':
      try:
        self._editView.SetIndent(int(style['Size']))
      except TypeError, err:
        self._editView.SetIndent(4)
    else:
      self._editView.SetIndent(4)

    # set indentation guides
    if style.has_key('ShowIndentGuide') and style['ShowIndentGuide'] != '':
      if style['ShowIndentGuide'].lower() == 'true':
        self._editView.SetIndentationGuides(True)
      else:
        self._editView.SetIndentationGuides(False)
    else:
      self._editView.SetIndent(True)

    # set backspace unindents
    if style.has_key('BackspaceUnindents') and style['BackspaceUnindents'] != '':
      if style['BackspaceUnindents'].lower() == 'true':
        self._editView.SetBackSpaceUnIndents(True)
      else:
        self._editView.SetBackSpaceUnIndents(False)
    else:
      self._editView.SetBackSpaceUnIndents(True)

    # set tab indents
    if style.has_key('TabIndents') and style['TabIndents'] != '':
      if style['TabIndents'].lower() == 'true':
        self._editView.SetTabIndents(True)
      else:
        self._editView.SetTabIndents(False)
    else:
      self._editView.SetTabIndents(True)

    # set tab width
    if style.has_key('TabWidth') and style['TabWidth'] != '':
      try:
        self._editView.SetTabWidth(int(style['TabWidth']))
      except TypeError, err:
        self._editView.SetTabWidth(4)
    else:
      self._editView.SetTabWidth(4)

    # set use tabs
    if style.has_key('UseTabs') and style['UseTabs'] != '':
      if style['UseTabs'].lower() == 'true':
        self._editView.SetUseTabs(True)
      else:
        self._editView.SetUseTabs(False)
    else:
      self._editView.SetUseTabs(True)

    # set white space
    if style.has_key('ViewWhitespace') and style['ViewWhitespace'] != '':
      if style['ViewWhitespace'].lower() == 'true':
        self._editView.SetViewWhiteSpace(True)
      else:
        self._editView.SetViewWhiteSpace(False)
    else:
      self._editView.SetViewWhiteSpace(True)

  def setEOL(self, eol_style=None):
    # EOL: Since we are loading/saving ourselves, and the
    # strings will always have \n's in them, set the STC to
    # edit them that way.
    viewEOL = False
    if not eol_style is None and eol_style.has_key('ShowEOL') and eol_style['ShowEOL'].lower() == 'true':
      viewEOL = True
      
    self._editView.SetEOLMode(wx.stc.STC_EOL_LF)

    self._editView.SetViewEOL(viewEOL)

  def setEdgeMode(self, edge_mode=None):
    maxColumns = 256
    if not edge_mode is None and edge_mode.has_key('Edge'):
      try:
        maxColumns = int(edge_mode['MaxColumns'])
      except:
        pass
    
    self._editView.SetEdgeMode(stc.STC_EDGE_BACKGROUND)

    self._editView.SetEdgeColumn(maxColumns)

  def setMargins(self, margins=None):
    self._editView.SetMarginType(0, stc.STC_MARGIN_NUMBER)
    self._editView.SetMarginWidth(0, 35)
    self._editView.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "size:8,face:Courier New")

    self._editView.SetMarginType(1, stc.STC_MARGIN_SYMBOL)
    self._editView.SetMarginMask(1, stc.STC_MASK_FOLDERS)
    self._editView.SetMarginSensitive(1, True)
    self._editView.SetMarginWidth(1, 12)

  def setMarker(self, marker_style=None):
    styles = stylesDefination.getMarkerStyles()

    style = styles['Square']
    fgcolor = 'white'
    bgcolor = '#404040'

    if not marker_style is None and marker_style.has_key('Style') and styles.has_key(marker_style['Style']):
      style = styles[marker_style['Style']]

    if not marker_style is None and marker_style.has_key('FgColor') and styles.has_key(marker_style['FgColor']):
      fgcolor = marker_style['FgColor']
      
    if not marker_style is None and marker_style.has_key('BgColor') and styles.has_key(marker_style['BgColor']):
      bgcolor = marker_style['BgColor']

    for key, value in style.items():
      try:
        self._editView.MarkerDefine(key, value, fgcolor, bgcolor)
      except:
        pass
    
  def setGlobalStyle(self, global_style=None):
    # - get global settings ------------------------
    font = 'Courier'
    if global_style.has_key('Name') and global_style['Name'] != '':
      font = global_style['Name']

    size = 10
    if global_style.has_key('Size') and global_style['Size'] != '':
      try:
        size = int(global_style['Size'])
      except TypeError, err:
        pass

    bold = 'false'
    if global_style.has_key('Bold') and global_style['Bold'] != '':
      bold = global_style['Bold']

    fgcolor = 'black'
    if global_style.has_key('FgColor') and global_style['FgColor'] != '':
      fgcolor = global_style['FgColor']

    bgcolor = 'white'
    if global_style.has_key('BgColor') and global_style['BgColor'] != '':
      bgcolor = global_style['BgColor']
      
    stylestr = self.getHighlightStyleString((font, size, fgcolor, bgcolor, bold, 'false'))

    tracer.writeln('Editor global style: %s' % stylestr)
    
    # - set global settings ------------------------
    self._editView.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, stylestr)
    self._editView.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER, stylestr)
    self._editView.StyleSetSpec(wx.stc.STC_STYLE_CONTROLCHAR, stylestr)
    self._editView.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT, stylestr)
    self._editView.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD, stylestr)

    self._editView.StyleClearAll()

  def setHighlightStyle(self, highlight_style=None):
    # get style defination
    if self._stylesDef is None:
      return

    # - get styles ---------------------------------
    style = None
    if highlight_style is None:
      tracer.writeln('Highlight style not define, use default.')
      style = self._stylesDef.getDefaultStyles()
    else:
      style = highlight_style

    # - set special language settings --------------
    symbols = self._stylesDef.getHighlightSymbols()
    if symbols is None:
      return

    for key, value in symbols.items():
      style_value = self.splitHighlistStyleString(style[key])
      style_str = self.getHighlightStyleString(style_value)
      tracer.writeln('%s style: %s' % (key, style_str))
      self._editView.StyleSetSpec(value, style_str)

  def setCaretFg(self, caret_style=None):
    if caret_style is None:
      self._editView.SetCaretForeground("BLACK")
    else:
      if caret_style.has_key('Color') and caret_style['Color'] != '':
        self._editView.SetCaretForeground(caret_style['Color'].upper())

  def splitHighlistStyleString(self, string):
    tracer.writeln('style setting string before split is %s' % string)
    splits = string.split(',')
    results = []
    for s in splits:
      results.append(s.strip(' \t'))
    return results

  def getHighlightStyleString(self, style_settings=None, eol=False):
    if style_settings is None:
      style_settings = ['Courier','10','black','white','false', 'false']

    tracer.writeln('style settings are %s' % str(style_settings))

    assert len(style_settings) > 5

    style_str = 'face:%s,size:%s,fore:%s,back:%s' % (style_settings[0], style_settings[1], style_settings[2], style_settings[3])

    if style_settings[4].lower() == 'true':
      style_str = '%s,%s' % (style_str, 'bold')

    underline = ''
    if style_settings[5].lower() == 'true':
      style_str = '%s,%s' % (style_str, 'underline')

    if eol:
      style_str += ',eol'

    return style_str